1. Field of the Invention
The present invention relates to computer.programming and, in particular, to methods for debugging software programs during development and after deployment.
2. Description of the Related Art
Computer programs (software) are typically developed by programmers (program developers) writing the code for the program with the aid of various debugging or debug techniques. For example, when a program under development is compiled and does not run properly, it must be debugged to determine the coding error. Debugging, therefore, refers to analysis of program operation to determine where coding errors are in the source code and to subsequent modifications to the program to avoid the problems caused by the or other errors.
Further, after a version of a program is compiled and implemented, if a problem develops there is also a need to perform xe2x80x9cfield debuggingxe2x80x9d. Field debugging refers to debugging an already-existing program which has already been developed, compiled, and provided to an end user or customer for use. For example, a program is developed during a development phase by program developers, during which phase debugging is performed in attempt to ensure that the program runs properly and robustly. Thereafter, a final version of the program code is compiled and shipped to various end users. The end users install the software on end use or xe2x80x9ctargetxe2x80x9d computer systems. When a problem is reported by the user, software developers need to analyze the program as implemented in the users"" computer system and environment to attempt to debug the remaining errors.
In some cases, some conventional debugging techniques or debuggers are not useful because, for example, the debugger requires the code to be paused while running or to run at less than emulations speeds, which can compromise the result for some types of programs where it is important that the program not be paused or run at less than full speed.
A debugging technique employing print statements is sometimes used, which does not pause the program while it is being tested or run. In the print statement approach, print statements are embedded at strategic locations within the code. These are designed to print out the current values of various variables, program states, and the like, typically along with an explanatory accompanying text message. A typical print statement, for example, might be PRINT(xe2x80x9cI AM IN STATExe2x80x9d, StateID), where the StateID parameter is a current state of the program code. The use of print statements in this manner allows the program developer to track the progress of the code without using additional debuggers or emulators.
Such debug output (debug output string) is typically routed to designated pins of a special debug port, e.g. on the backplane of the computer (e.g., a PC) which is running the program. A terminal may be coupled thereto so that the program developer can view the output of the debug print statements on a monitor of the terminal. The debug port is typically not intended for access by customers.
A print statement is typically a defined statement in the high-level programming language (e.g., C++) in which the program developer works to develop the program code. Thus, when the program is running (after it is compiled), when the instruction corresponding to the print statement is reached during program flow, it is always executed, like any other statement. The print statement is typically xe2x80x9cblocking,xe2x80x9d meaning that it has priority until the print is completed, and thus blocks other processing of the processor. Thus, the use of print statements for debugging purposes is not without cost, because such statements can take up a substantial portion of the program code and CPU (central processing unit, or processor) time or processing bandwidth (e.g., 10% of each), thereby slowing down the execution of the program when it is running. CPU time is required, for example, for formatting and copying the resulting debug output string into a trace buffer, which is used to temporarily buffer, format, store, and display debut output strings produced.
In an attempt to gain the advantage of the print statement debug strategy without its attendant disadvantages, the print statements are sometimes removed from the program code after the code is completed, and prior to its final compile. This may be done, for example, by using a print macro which, during code development, contains the standard print statement. Before compiling the final version of the program and shipping the compiled code (which comprises instructions) to the customer or end user, the debug print macro definition is changed to null or nothing (this is sometimes referred to as compiling the macro to null). One drawback of this approach, however, is that if there is subsequently a problem xe2x80x9cin the field,xe2x80x9d the compiled code for the final program will not contain the previously-used debug print statements and thus will not be providing the debug data at the debug port. Thus, the program developer will not have access to this useful debugging data. Another problem with this approach is that the behavior of the computer system running the program, especially with respect to timing, is different for the final version (which has the macro compiled out) than for the version used during testing and development (which has the macro compiled in).
A modification of the above debug print statement approaches involves using a special macro, which may be referred to as a xe2x80x9ctracexe2x80x9d macro, which contains print statements which are selectively enabled based on developer-selected masks, based on some specified rules of filtering. The trace macro may be referred to as a trace statement for simplicity, even though trace is not a defined statement in the programming language. Thus, each trace statement provides a filterable debug output, i.e. a debug output which can be selectively enabled based on certain masks. Like a print statement, a trace statement can be used to cause various messages or other debug information to be printed or displayed on a monitor.
Each trace statement may be one of one or more classes or types of trace statements, where the mask set is able to selectively enable or disable certain trace classes. For example, each program under development may have several major software or code objects or portions, each of which may have a different code developer. Each such object may be assigned its own trace identifier (TraceID), so that only the trace statements for a given software object are enabled. Subsets of the trace statements for a particular object may be selected by applying a mask to further subdivide the trace statements which can be selectively enabled. The trace statements in a given set of code may thus be grouped according to the code object in which it resides or according to the developer of that code. Thus, the use of such debug trace statements allows the program developer to specify and thus enable only the subset of debug messages which are of interest.
Unlike a print statement, which is always executed by the processor and which is blocking, a trace statement is a request to send something to be printed. This request is queued, and the information is either printed or not, based on a trace filter which indicates whether or not the particular trace category to which the trace statement belongs is of interest (has been enabled or set). The use of trace macros or statements provides some savings in terms of CPU usage, since if some or all of the trace statements are disabled, then less CPU time is required. Further, trace statements are often implemented on a separate thread and thus non-blocking of more important system operations and of lower priority than print statements, which are inherently on the calling thread. Trace statements therefore do not interrupt higher priority processing.
Nevertheless, when trace statements are employed, some CPU time is still required, if only to queue each trace statement""s conditional print request and to check to determine if its mask is set or not. Thus, even if all the trace statements are disabled (the default for a completed, compiled program already shipped to customers and running xe2x80x9cin the fieldxe2x80x9d), the computer still runs more slowly than it would if it had no trace statements. Further, the code size problem encountered when using debug print statements is not improved by using trace statements, since each trace macro is still compiled into the code.
Trace statements may be compiled to null before final compilation and shipping to customers, as described above with respect to print statements, but again the problem with this approach is that the code developer is denied the use of the debug output diagnostics in the field.
As explained above, the debug port is typically not intended for access by customers, whether the debug output is provided from print statements or trace statements. Further, the default mask or filter setting for trace statements is off, to further prevent unauthorized users such as customers from gaining access to the debug output. One problem that can arise when providing debug output on the debug port is that a customer gains access to this information and is confused by the debug messages, and erroneously believes there is a bug or problem with the program. This can annoy, confuse, frustrate the customer and/or cause him to complain to the vendor.
The source code for a computer program contains a plurality of debug output statements for providing debug output strings, each debug output statement comprising a fixed-size text string. The text string of each debug output statement is replaced with a unique text string number to provide stripped source code. A number-to-string mapping table for translating each unique text string number into a corresponding text string is constructed. The stripped source code is compiled to provide stripped object code.
The stripped object code for the computer program is run on a target computer. A debug computer receives debug output strings from corresponding debug output statements of the computer program, each debug output string having a unique text string number. The debug computer translates the unique text string number for each debug output string into a corresponding text string using the number-to-string mapping table, and replaces the unique text string number in the debug output string with the corresponding text string to provide an un-stripped debug output string. The debug computer displays the un-stripped debug output string.